package com.jwds.digital.bios.business.service.service.belt.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jwds.digital.bios.business.core.infrastructure.entity.basic.BasicDevice;
import com.jwds.digital.bios.business.core.infrastructure.entity.belt.BeltDayTargetHis;
import com.jwds.digital.bios.business.core.infrastructure.entity.flow.FlowBasic;
import com.jwds.digital.bios.business.core.infrastructure.mapper.basic.BasicDeviceMapper;
import com.jwds.digital.bios.business.core.infrastructure.mapper.belt.BeltPerformanceDayMapper;
import com.jwds.digital.bios.business.core.infrastructure.mapper.belt.BeltPerformanceWeekMapper;
import com.jwds.digital.bios.business.core.infrastructure.mapper.belt.BeltRoutePerformanceDayMapper;
import com.jwds.digital.bios.business.core.infrastructure.mapper.flow.FlowBasicMapper;
import com.jwds.digital.bios.business.core.infrastructure.vo.belt.*;
import com.jwds.digital.bios.business.core.infrastructure.vo.feign.FlowBasicRespVO;
import com.jwds.digital.bios.business.service.service.belt.IBeltDayTargetHisService;
import com.jwds.digital.bios.business.service.service.belt.IBeltRoutePerformanceWeekService;
import com.jwds.digital.bios.business.core.infrastructure.dto.belt.BeltRoutePerformanceWeekReqDTO;
import com.jwds.digital.bios.business.core.infrastructure.dto.belt.assembler.BeltRoutePerformanceWeekAssembler;
import com.jwds.digital.bios.business.core.infrastructure.entity.belt.BeltRoutePerformanceWeek;
import com.jwds.digital.bios.business.core.infrastructure.mapper.belt.BeltRoutePerformanceWeekMapper;
import com.jwds.digital.bios.business.core.exceptions.RecordNotFoundException;
import com.jwds.tdc.framework.application.lib.page.PageRequest;
import com.jwds.tdc.framework.application.lib.page.PageResponse;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.YearMonth;
import java.time.temporal.ChronoUnit;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 线路效能周表实现类
 *
 * @author 林柏云
 * @date 2024-10-24
 */
@Slf4j
@Service
public class BeltRoutePerformanceWeekServiceImpl extends ServiceImpl<BeltRoutePerformanceWeekMapper, BeltRoutePerformanceWeek> implements IBeltRoutePerformanceWeekService {

    @Autowired
    private BeltRoutePerformanceWeekMapper baseMapper;

    @Autowired
    private IBeltDayTargetHisService beltDayTargetHisService;

    @Override
    public BeltRoutePerformanceWeekRespVO queryById(Long id) {
        if (id == null) {
            return null;
        }
        BeltRoutePerformanceWeek entity = baseMapper.selectById(id);
        return BeltRoutePerformanceWeekAssembler.entity2dto(entity);
    }

    @Override
    public PageResponse<BeltRoutePerformanceWeekRespVO> page(PageRequest<BeltRoutePerformanceWeekReqDTO> request) {
        BeltRoutePerformanceWeekReqDTO condition = request.getQueryCondition();
        Page<BeltRoutePerformanceWeekRespVO> page = new Page<>(request.getPageIndex(), request.getPageSize());
        IPage<BeltRoutePerformanceWeekRespVO> pageData = baseMapper.pageQuery(page, condition);
        return new PageResponse<>((Page<?>) pageData, pageData.getRecords());
    }

    @Override
    public List<BeltRoutePerformanceWeekRespVO> list(BeltRoutePerformanceWeekReqDTO reqDto) {
        return baseMapper.queryList(reqDto);
    }

    @Override
    public void add(BeltRoutePerformanceWeekReqDTO reqDto) {
        BeltRoutePerformanceWeek entity = BeltRoutePerformanceWeekAssembler.dto2entity(reqDto);
        baseMapper.insert(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchAdd(List<BeltRoutePerformanceWeekReqDTO> dtoList) {
        dtoList.forEach(this::add);
    }

    @Override
    public void update(BeltRoutePerformanceWeekReqDTO reqDto) {
        BeltRoutePerformanceWeek oldEntity = baseMapper.selectById(reqDto.getId());
        if (oldEntity == null) {
            throw new RecordNotFoundException();
        }
        BeltRoutePerformanceWeek newEntity = BeltRoutePerformanceWeekAssembler.dto2entity(reqDto, oldEntity);
        baseMapper.updateById(newEntity);
    }

    @Override
    public void delete(Long id) {
        BeltRoutePerformanceWeek oldEntity = baseMapper.selectById(id);
        if (oldEntity == null) {
            throw new RecordNotFoundException();
        }
        baseMapper.deleteById(id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchDelete(List<Long> ids) {
        for (Long id : ids) {
            delete(id);
        }
    }

    @Autowired
    private BeltRoutePerformanceDayMapper beltRoutePerformanceDayMapper;


    @Override
    public BeltRoutePerformanceWeekRespVO getLineEfficiencyWeek(Long routeId) {
        // 线路效能周基本信息
        BeltRoutePerformanceWeekRespVO lineEfficiencyWeek = baseMapper.getLineEfficiencyWeek(routeId, 1);

        if (lineEfficiencyWeek == null) {
            return null;
        }

        // 启动空转时间
        BigDecimal between = new BigDecimal(ChronoUnit.WEEKS.between(lineEfficiencyWeek.getStartTime(), lineEfficiencyWeek.getEndTime()));
        lineEfficiencyWeek.setStartIdleTimeInOperation(between);


        // 停止空转时间
        BigDecimal emptyTime = new BigDecimal(ChronoUnit.WEEKS.between(lineEfficiencyWeek.getStartEmptyTime(), lineEfficiencyWeek.getEndEmptyTime()));
        lineEfficiencyWeek.setEndIdleTimeInOperation(emptyTime);

        // 运行中空载时间
        lineEfficiencyWeek.setIdleTimeInOperation(lineEfficiencyWeek.getNoLoadRuntime().subtract(between).subtract(emptyTime));

        // 启动空转时间占比
        lineEfficiencyWeek.setStartIdleTimeConsumptionRatio(between.divide(lineEfficiencyWeek.getNoLoadRuntime(), 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)));

        // 停止空转时间占比
        lineEfficiencyWeek.setEndIdleTimeConsumptionRatio(emptyTime.divide(lineEfficiencyWeek.getNoLoadRuntime(), 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)));

        // 运行中空载时间占比
        lineEfficiencyWeek.setInOperationIdleTImeConsumptionRatio(lineEfficiencyWeek.getIdleTimeInOperation().divide(lineEfficiencyWeek.getNoLoadRuntime(), 2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)));

        // 运行中空载能耗
        lineEfficiencyWeek.setIdleEnergyInOperation(lineEfficiencyWeek.getNoLoadPowerConsumption().subtract(lineEfficiencyWeek.getStartNoLoadPowerConsumption()).subtract(lineEfficiencyWeek.getEndNoLoadPowerConsumption()));

        // 运行中空载能耗占比
        lineEfficiencyWeek.setInOperationIdleEnergyConsumptionRatio(lineEfficiencyWeek.getIdleEnergyInOperation().divide(lineEfficiencyWeek.getNoLoadPowerConsumption()));

        // 启动空载能耗占比
        lineEfficiencyWeek.setStartIdleTimeConsumptionRatio(lineEfficiencyWeek.getStartNoLoadPowerConsumption().divide(lineEfficiencyWeek.getNoLoadPowerConsumption()));

        // 停止空载能耗占比
        lineEfficiencyWeek.setEndIdleTimeConsumptionRatio(lineEfficiencyWeek.getEndNoLoadPowerConsumption().divide(lineEfficiencyWeek.getNoLoadPowerConsumption()));


        //合格线
        BeltDayTargetHis beltDayTargetHis = beltDayTargetHisService.selectLatest();
        lineEfficiencyWeek.setQualifiedLine(beltDayTargetHis.getWorkEfficiency());

        //平均电机运行效率==------------------------------------
        List<AverageMotorOperatingEfficiencyStats> averageMotorOperatingEfficiencyList = beltRoutePerformanceDayMapper.getAverageMotorOperatingEfficiencyStats(routeId);
        if (averageMotorOperatingEfficiencyList == null) {
            return null;
        }
        lineEfficiencyWeek.setAverageMotorOperatingEfficiencyStats(averageMotorOperatingEfficiencyList);

/*// 计算上周的开始时间和结束时间
        LocalDate now = LocalDate.now().minusWeeks(1);
        LocalDate weekStart = now.minusDays(now.getDayOfWeek().getValue() - 1);
        LocalDate weekEnd = weekStart.plusDays(6);
        LocalDateTime startTime = weekStart.atStartOfDay();
        LocalDateTime endTime = weekEnd.atTime(23, 59, 59);*/


        // 将开始日期转换为 LocalDateTime，时间为当天的开始时间（00:00:00）
        LocalDateTime startTime = YearMonth.from(LocalDate.now()).atDay(1).atStartOfDay();

        // 将结束日期转换为 LocalDateTime，时间为当天的结束时间（23:59:59）
        LocalDateTime endTime = YearMonth.from(LocalDate.now()).atDay(1).plusMonths(1).minusDays(1).atTime(LocalTime.MAX);

        /*// 计算一周的开始时间和结束时间
        LocalDate now = LocalDate.now();
        LocalDate weekStart = now.minusDays(now.getDayOfWeek().getValue() - 1);
        LocalDate weekEnd = weekStart.plusDays(6);
        LocalDateTime startTime = weekStart.atStartOfDay();
        LocalDateTime endTime = weekEnd.atTime(23, 59, 59);*/

        List<BeltRoutePerformanceWeekRespVO> week = baseMapper.getLineEfficiencyWeekS(routeId, startTime, endTime);

        List<LoadRateAndWorkingEfficiency> loadRateAndWorkingEfficiencies = week.stream().map(h -> {
            LoadRateAndWorkingEfficiency loadRateAndWorkingEfficiency = new LoadRateAndWorkingEfficiency();
            loadRateAndWorkingEfficiency.setWorkEfficiency(h.getWorkEfficiency());
            loadRateAndWorkingEfficiency.setAvgNoLoadRate(h.getAvgNoLoadRate());
            loadRateAndWorkingEfficiency.setAvgLoadRate(h.getAvgLoadRate());
            loadRateAndWorkingEfficiency.setBelongDate(h.getBelongDate());
            return loadRateAndWorkingEfficiency;
        }).collect(Collectors.toList());

        lineEfficiencyWeek.setLoadRateAndWorkingEfficiencyList(loadRateAndWorkingEfficiencies);

        return lineEfficiencyWeek;
    }

    @Autowired
    private BasicDeviceMapper basicDeviceMapper;
    @Autowired
    private FlowBasicMapper flowBasicMapper;

    @Autowired
    private BeltPerformanceWeekMapper beltPerformancedWeekMapper;
    @Autowired
    private BeltRoutePerformanceWeekMapper beltRoutePerformanceWeekMapper;

    @Override
    public List<Map<String, Object>> getBeltInfoById(Long id) {
        // 根据 ID 查询 flow_basic 表
        FlowBasicRespVO flowBasic = flowBasicMapper.searchById(id);
        if (flowBasic == null) {
            return null;
        }

        // 将 flow_name 按下划线 _ 分割
        String flowName = flowBasic.getFlowName();
        List<String> beltNames = Arrays.asList(flowName.split("-"));

        // 根据 beltName 查询 basic_device 表
        List<BasicDevice> devices = basicDeviceMapper.selectByDeviceNames(beltNames);
        if (devices == null) {
            return null;
        }
        // 获取所有皮带的 ID
        List<Integer> beltIds = devices.stream()
                .map(BasicDevice::getId)
                .collect(Collectors.toList());

        // 统计所有皮带的总长度
        BigDecimal totalBeltLength = flowBasic.getFlowDistance();
        /*double totalBeltLength = devices.stream()
                .filter(device -> device != null && device.getDeviceLength() != null)
                .mapToDouble(device -> device.getDeviceLength().doubleValue())
                .sum();*/

        // 根据 beltId 查询 belt_performance_week 表
        List<BeltPerformanceWeekRespVO> performances = beltPerformancedWeekMapper.selectByBeltIds(beltIds);
        if (performances == null) {
            return null;
        }
        // 计算每条皮带的运输效率和运输能耗
        Map<Integer, BasicDevice> deviceMap = devices.stream()
                .collect(Collectors.toMap(BasicDevice::getId, device -> device));

        List<Map<String, Object>> result = performances.stream().map(performance -> {
            BasicDevice device = deviceMap.get(performance.getBeltId().intValue());
            if (device == null) {
                // 返回一个空的 Map 或者跳过当前项
                return new HashMap<String, Object>(); // 返回一个空的 Map
            }
            BigDecimal totalTransport = performance.getTotalTransport() == null ? BigDecimal.ZERO : performance.getTotalTransport();
            BigDecimal allRuntime = performance.getLoadRuntime() == null ? BigDecimal.ZERO : performance.getLoadRuntime();
            BigDecimal totalPowerConsumption = performance.getTotalPowerConsumption() == null ? BigDecimal.ZERO : performance.getTotalPowerConsumption();
            // 检查 totalTransport 和 allRuntime 是否为 null
            if (totalTransport == null || allRuntime == null) {
                log.error("totalTransport or allRuntime is null for beltId: {}", performance.getId());
                return null;
            }
            BigDecimal transportEfficiency = allRuntime.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : totalTransport.divide(allRuntime, 4, BigDecimal.ROUND_HALF_UP);
            BigDecimal transportEnergyConsumption = totalTransport.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : totalPowerConsumption.divide(totalTransport, 4, BigDecimal.ROUND_HALF_UP);

            return new HashMap<String, Object>() {{
                put("beltName", device.getDeviceName());
                put("beltLength", device.getDeviceLength());
                put("transportEfficiency", transportEfficiency);
                put("transportEnergyConsumption", transportEnergyConsumption);
            }};
        }).collect(Collectors.toList());

        // 获取整条线路的性能记录
        BeltRoutePerformanceWeekRespVO respVO = beltRoutePerformanceWeekMapper.searchByRouteId(id);
        if (respVO == null) {
            return null;
        }
        BigDecimal totalRouteTransport = respVO.getTotalTransport();
        BigDecimal totalRouteRuntime = respVO.getAllRuntime();
        BigDecimal totalRoutePowerConsumption = respVO.getTotalPowerConsumption();
        // 检查 totalRouteTransport 和 totalRouteRuntime 是否为 null
        if (totalRouteTransport == null || totalRouteRuntime == null) {
            log.error("totalRouteTransport or totalRouteRuntime is null for id: {}", id);
            return null;
        }
        BigDecimal routeTransportEfficiency = totalRouteRuntime.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : totalRouteTransport.divide(totalRouteRuntime, 4, BigDecimal.ROUND_HALF_UP);
        BigDecimal routeTransportEnergyConsumption = totalRouteTransport.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : totalRoutePowerConsumption.divide(totalRouteTransport, 4, BigDecimal.ROUND_HALF_UP);

        // 将总长度、整条线路的运输效率和运输能耗以及线路名称添加到结果中
        Map<String, Object> summary = new HashMap<>();
        summary.put("totalBeltLength", totalBeltLength);
        summary.put("routeTransportEfficiency", routeTransportEfficiency);
        summary.put("routeTransportEnergyConsumption", routeTransportEnergyConsumption);
        summary.put("flowName", flowName); // 添加整条线路的名称
        result.add(summary);

        return result;

    }


}